home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / PROGS / EXAMPLES / rendereps.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  19.4 KB  |  710 lines

  1.  
  2. /* Copyright (c) Mark J. Kilgard, 1997. */
  3.  
  4. /* This program is freely distributable without licensing fees 
  5.    and is provided without guarantee or warrantee expressed or 
  6.    implied. This program is -not- in the public domain. */
  7.  
  8. /* Example showing how to use OpenGL's feedback mode to capture
  9.    transformed vertices and output them as Encapsulated PostScript.
  10.    Handles limited hidden surface removal by sorting and does
  11.    smooth shading (albeit limited due to PostScript). */
  12.  
  13. /* Compile: cc -o rendereps rendereps.c -lglut -lGLU -lGL -lXmu -lXext -lX11 -lm */
  14.  
  15. #include <assert.h>
  16. #include <math.h>
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <GL/glut.h>
  20.  
  21. /* OpenGL's GL_3D_COLOR feedback vertex format. */
  22. typedef struct _Feedback3Dcolor {
  23.   GLfloat x;
  24.   GLfloat y;
  25.   GLfloat z;
  26.   GLfloat red;
  27.   GLfloat green;
  28.   GLfloat blue;
  29.   GLfloat alpha;
  30. } Feedback3Dcolor;
  31.  
  32. int blackBackground = 0;  /* Initially use a white background. */
  33. int lighting = 0;       /* Initially disable lighting. */
  34. int polygonMode = 1;    /* Initially show wireframe. */
  35. int object = 1;         /* Initially show the torus. */
  36.  
  37. GLfloat angle = 0.0;    /* Angle of rotation for object. */
  38. int moving, begin;      /* For interactive object rotation. */
  39. int size = 1;           /* Size of lines and points. */
  40.  
  41. /* How many feedback buffer GLfloats each of the three objects need. */
  42. int objectComplexity[3] =
  43. {6000, 14000, 380000};  /* Teapot requires ~1.5 megabytes for
  44.                            its feedback results! */
  45.  
  46. /* render gets called both by "display" (in OpenGL render mode)
  47.    and by "outputEPS" (in OpenGL feedback mode). */
  48. void
  49. render(void)
  50. {
  51.   glPushMatrix();
  52.   glRotatef(angle, 0.0, 1.0, 0.0);
  53.   switch (object) {
  54.   case 0:
  55.     glutSolidSphere(1.0, 10, 10);
  56.     break;
  57.   case 1:
  58.     glutSolidTorus(0.5, 1.0, 15, 15);
  59.     break;
  60.   case 2:
  61.     glutSolidTeapot(1.0);
  62.     break;
  63.   }
  64.   glPopMatrix();
  65. }
  66.  
  67. void
  68. display(void)
  69. {
  70.   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  71.   render();
  72.   glutSwapBuffers();
  73. }
  74.  
  75. void
  76. updateBackground(void)
  77. {
  78.   if (blackBackground) {
  79.     /* Clear to black. */
  80.     glClearColor(0.0, 0.0, 0.0, 1.0);
  81.   } else {
  82.     /* Clear to white. */
  83.     glClearColor(1.0, 1.0, 1.0, 1.0);
  84.   }
  85. }
  86.  
  87. void
  88. updateLighting(void)
  89. {
  90.   if (lighting) {
  91.     glEnable(GL_LIGHTING);
  92.   } else {
  93.     glDisable(GL_LIGHTING);
  94.   }
  95. }
  96.  
  97. void
  98. updatePolygonMode(void)
  99. {
  100.   switch (polygonMode) {
  101.   case 0:
  102.     glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
  103.     break;
  104.   case 1:
  105.     glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
  106.     break;
  107.   case 2:
  108.     glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  109.     break;
  110.   }
  111. }
  112.  
  113. /* Write contents of one vertex to stdout. */
  114. void
  115. print3DcolorVertex(GLint size, GLint * count,
  116.   GLfloat * buffer)
  117. {
  118.   int i;
  119.  
  120.   printf("  ");
  121.   for (i = 0; i < 7; i++) {
  122.     printf("%4.2f ", buffer[size - (*count)]);
  123.     *count = *count - 1;
  124.   }
  125.   printf("\n");
  126. }
  127.  
  128. void
  129. printBuffer(GLint size, GLfloat * buffer)
  130. {
  131.   GLint count;
  132.   int token, nvertices;
  133.  
  134.   count = size;
  135.   while (count) {
  136.     token = buffer[size - count];
  137.     count--;
  138.     switch (token) {
  139.     case GL_PASS_THROUGH_TOKEN:
  140.       printf("GL_PASS_THROUGH_TOKEN\n");
  141.       printf("  %4.2f\n", buffer[size - count]);
  142.       count--;
  143.       break;
  144.     case GL_POINT_TOKEN:
  145.       printf("GL_POINT_TOKEN\n");
  146.       print3DcolorVertex(size, &count, buffer);
  147.       break;
  148.     case GL_LINE_TOKEN:
  149.       printf("GL_LINE_TOKEN\n");
  150.       print3DcolorVertex(size, &count, buffer);
  151.       print3DcolorVertex(size, &count, buffer);
  152.       break;
  153.     case GL_LINE_RESET_TOKEN:
  154.       printf("GL_LINE_RESET_TOKEN\n");
  155.       print3DcolorVertex(size, &count, buffer);
  156.       print3DcolorVertex(size, &count, buffer);
  157.       break;
  158.     case GL_POLYGON_TOKEN:
  159.       printf("GL_POLYGON_TOKEN\n");
  160.       nvertices = buffer[size - count];
  161.       count--;
  162.       for (; nvertices > 0; nvertices--) {
  163.         print3DcolorVertex(size, &count, buffer);
  164.       }
  165.     }
  166.   }
  167. }
  168.  
  169. GLfloat pointSize;
  170.  
  171. static char *gouraudtriangleEPS[] =
  172. {
  173.   "/bd{bind def}bind def /triangle { aload pop   setrgbcolor  aload pop 5 3",
  174.   "roll 4 2 roll 3 2 roll exch moveto lineto lineto closepath fill } bd",
  175.   "/computediff1 { 2 copy sub abs threshold ge {pop pop pop true} { exch 2",
  176.   "index sub abs threshold ge { pop pop true} { sub abs threshold ge } ifelse",
  177.   "} ifelse } bd /computediff3 { 3 copy 0 get 3 1 roll 0 get 3 1 roll 0 get",
  178.   "computediff1 {true} { 3 copy 1 get 3 1 roll 1 get 3 1 roll 1 get",
  179.   "computediff1 {true} { 3 copy 2 get 3 1 roll  2 get 3 1 roll 2 get",
  180.   "computediff1 } ifelse } ifelse } bd /middlecolor { aload pop 4 -1 roll",
  181.   "aload pop 4 -1 roll add 2 div 5 1 roll 3 -1 roll add 2 div 3 1 roll add 2",
  182.   "div 3 1 roll exch 3 array astore } bd /gouraudtriangle { computediff3 { 4",
  183.   "-1 roll aload 7 1 roll 6 -1 roll pop 3 -1 roll pop add 2 div 3 1 roll add",
  184.   "2 div exch 3 -1 roll aload 7 1 roll exch pop 4 -1 roll pop add 2 div 3 1",
  185.   "roll add 2 div exch 3 -1 roll aload 7 1 roll pop 3 -1 roll pop add 2 div 3",
  186.   "1 roll add 2 div exch 7 3 roll 10 -3 roll dup 3 index middlecolor 4 1 roll",
  187.   "2 copy middlecolor 4 1 roll 3 copy pop middlecolor 4 1 roll 13 -1 roll",
  188.   "aload pop 17 index 6 index 15 index 19 index 6 index 17 index 6 array",
  189.   "astore 10 index 10 index 14 index gouraudtriangle 17 index 5 index 17",
  190.   "index 19 index 5 index 19 index 6 array astore 10 index 9 index 13 index",
  191.   "gouraudtriangle 13 index 16 index 5 index 15 index 18 index 5 index 6",
  192.   "array astore 12 index 12 index 9 index gouraudtriangle 17 index 16 index",
  193.   "15 index 19 index 18 index 17 index 6 array astore 10 index 12 index 14",
  194.   "index gouraudtriangle 18 {pop} repeat } { aload pop 5 3 roll aload pop 7 3",
  195.   "roll aload pop 9 3 roll 4 index 6 index 4 index add add 3 div 10 1 roll 7",
  196.   "index 5 index 3 index add add 3 div 10 1 roll 6 index 4 index 2 index add",
  197.   "add 3 div 10 1 roll 9 {pop} repeat 3 array astore triangle } ifelse } bd",
  198.   NULL
  199. };
  200.  
  201. GLfloat *
  202. spewPrimitiveEPS(FILE * file, GLfloat * loc)
  203. {
  204.   int token;
  205.   int nvertices, i;
  206.   GLfloat red, green, blue;
  207.   int smooth;
  208.   GLfloat dx, dy, dr, dg, db, absR, absG, absB, colormax;
  209.   int steps;
  210.   Feedback3Dcolor *vertex;
  211.   GLfloat xstep, ystep, rstep, gstep, bstep;
  212.   GLfloat xnext, ynext, rnext, gnext, bnext, distance;
  213.  
  214.   token = *loc;
  215.   loc++;
  216.   switch (token) {
  217.   case GL_LINE_RESET_TOKEN:
  218.   case GL_LINE_TOKEN:
  219.     vertex = (Feedback3Dcolor *) loc;
  220.  
  221.     dr = vertex[1].red - vertex[0].red;
  222.     dg = vertex[1].green - vertex[0].green;
  223.     db = vertex[1].blue - vertex[0].blue;
  224.  
  225.     if (dr != 0 || dg != 0 || db != 0) {
  226.       /* Smooth shaded line. */
  227.       dx = vertex[1].x - vertex[0].x;
  228.       dy = vertex[1].y - vertex[0].y;
  229.       distance = sqrt(dx * dx + dy * dy);
  230.  
  231.       absR = fabs(dr);
  232.       absG = fabs(dg);
  233.       absB = fabs(db);
  234.  
  235. #define Max(a,b) (((a)>(b))?(a):(b))
  236.  
  237. #define EPS_SMOOTH_LINE_FACTOR 0.06  /* Lower for better smooth 
  238.  
  239.                                         lines. */
  240.  
  241.       colormax = Max(absR, Max(absG, absB));
  242.       steps = Max(1.0, colormax * distance * EPS_SMOOTH_LINE_FACTOR);
  243.  
  244.       xstep = dx / steps;
  245.       ystep = dy / steps;
  246.  
  247.       rstep = dr / steps;
  248.       gstep = dg / steps;
  249.       bstep = db / steps;
  250.  
  251.       xnext = vertex[0].x;
  252.       ynext = vertex[0].y;
  253.       rnext = vertex[0].red;
  254.       gnext = vertex[0].green;
  255.       bnext = vertex[0].blue;
  256.  
  257.       /* Back up half a step; we want the end points to be
  258.          exactly the their endpoint colors. */
  259.       xnext -= xstep / 2.0;
  260.       ynext -= ystep / 2.0;
  261.       rnext -= rstep / 2.0;
  262.       gnext -= gstep / 2.0;
  263.       bnext -= bstep / 2.0;
  264.     } else {
  265.       /* Single color line. */
  266.       steps = 0;
  267.     }
  268.  
  269.     fprintf(file, "%g %g %g setrgbcolor\n",
  270.       vertex[0].red, vertex[0].green, vertex[0].blue);
  271.     fprintf(file, "%g %g moveto\n", vertex[0].x, vertex[0].y);
  272.  
  273.     for (i = 0; i < steps; i++) {
  274.       xnext += xstep;
  275.       ynext += ystep;
  276.       rnext += rstep;
  277.       gnext += gstep;
  278.       bnext += bstep;
  279.       fprintf(file, "%g %g lineto stroke\n", xnext, ynext);
  280.       fprintf(file, "%g %g %g setrgbcolor\n", rnext, gnext, bnext);
  281.       fprintf(file, "%g %g moveto\n", xnext, ynext);
  282.     }
  283.     fprintf(file, "%g %g lineto stroke\n", vertex[1].x, vertex[1].y);
  284.  
  285.     loc += 14;          /* Each vertex element in the feedback
  286.                            buffer is 7 GLfloats. */
  287.  
  288.     break;
  289.   case GL_POLYGON_TOKEN:
  290.     nvertices = *loc;
  291.     loc++;
  292.  
  293.     vertex = (Feedback3Dcolor *) loc;
  294.  
  295.     if (nvertices > 0) {
  296.       red = vertex[0].red;
  297.       green = vertex[0].green;
  298.       blue = vertex[0].blue;
  299.       smooth = 0;
  300.       for (i = 1; i < nvertices; i++) {
  301.         if (red != vertex[i].red || green != vertex[i].green || blue != vertex[i].blue) {
  302.           smooth = 1;
  303.           break;
  304.         }
  305.       }
  306.       if (smooth) {
  307.         /* Smooth shaded polygon; varying colors at vetices. */
  308.         /* Break polygon into "nvertices-2" triangle fans. */
  309.         for (i = 0; i < nvertices - 2; i++) {
  310.           fprintf(file, "[%g %g %g %g %g %g]",
  311.             vertex[0].x, vertex[i + 1].x, vertex[i + 2].x,
  312.             vertex[0].y, vertex[i + 1].y, vertex[i + 2].y);
  313.           fprintf(file, " [%g %g %g] [%g %g %g] [%g %g %g] gouraudtriangle\n",
  314.             vertex[0].red, vertex[0].green, vertex[0].blue,
  315.             vertex[i + 1].red, vertex[i + 1].green, vertex[i + 1].blue,
  316.             vertex[i + 2].red, vertex[i + 2].green, vertex[i + 2].blue);
  317.         }
  318.       } else {
  319.         /* Flat shaded polygon; all vertex colors the same. */
  320.         fprintf(file, "newpath\n");
  321.         fprintf(file, "%g %g %g setrgbcolor\n", red, green, blue);
  322.  
  323.         /* Draw a filled triangle. */
  324.         fprintf(file, "%g %g moveto\n", vertex[0].x, vertex[0].y);
  325.         for (i = 1; i < nvertices; i++) {
  326.           fprintf(file, "%g %g lineto\n", vertex[i].x, vertex[i].y);
  327.         }
  328.         fprintf(file, "closepath fill\n\n");
  329.       }
  330.     }
  331.     loc += nvertices * 7;  /* Each vertex element in the
  332.                               feedback buffer is 7 GLfloats. */
  333.     break;
  334.   case GL_POINT_TOKEN:
  335.     vertex = (Feedback3Dcolor *) loc;
  336.     fprintf(file, "%g %g %g setrgbcolor\n", vertex[0].red, vertex[0].green, vertex[0].blue);
  337.     fprintf(file, "%g %g %g 0 360 arc fill\n\n", vertex[0].x, vertex[0].y, pointSize / 2.0);
  338.     loc += 7;           /* Each vertex element in the feedback
  339.                            buffer is 7 GLfloats. */
  340.     break;
  341.   default:
  342.     /* XXX Left as an excersie to the reader. */
  343.     printf("Incomplete implementation.  Unexpected token (%d).\n", token);
  344.     exit(1);
  345.   }
  346.   return loc;
  347. }
  348.  
  349. void
  350. spewUnsortedFeedback(FILE * file, GLint size, GLfloat * buffer)
  351. {
  352.   GLfloat *loc, *end;
  353.  
  354.   loc = buffer;
  355.   end = buffer + size;
  356.   while (loc < end) {
  357.     loc = spewPrimitiveEPS(file, loc);
  358.   }
  359. }
  360.  
  361. typedef struct _DepthIndex {
  362.   GLfloat *ptr;
  363.   GLfloat depth;
  364. } DepthIndex;
  365.  
  366. static int
  367. compare(const void *a, const void *b)
  368. {
  369.   DepthIndex *p1 = (DepthIndex *) a;
  370.   DepthIndex *p2 = (DepthIndex *) b;
  371.   GLfloat diff = p2->depth - p1->depth;
  372.  
  373.   if (diff > 0.0) {
  374.     return 1;
  375.   } else if (diff < 0.0) {
  376.     return -1;
  377.   } else {
  378.     return 0;
  379.   }
  380. }
  381.  
  382. void
  383. spewSortedFeedback(FILE * file, GLint size, GLfloat * buffer)
  384. {
  385.   int token;
  386.   GLfloat *loc, *end;
  387.   Feedback3Dcolor *vertex;
  388.   GLfloat depthSum;
  389.   int nprimitives, item;
  390.   DepthIndex *prims;
  391.   int nvertices, i;
  392.  
  393.   end = buffer + size;
  394.  
  395.   /* Count how many primitives there are. */
  396.   nprimitives = 0;
  397.   loc = buffer;
  398.   while (loc < end) {
  399.     token = *loc;
  400.     loc++;
  401.     switch (token) {
  402.     case GL_LINE_TOKEN:
  403.     case GL_LINE_RESET_TOKEN:
  404.       loc += 14;
  405.       nprimitives++;
  406.       break;
  407.     case GL_POLYGON_TOKEN:
  408.       nvertices = *loc;
  409.       loc++;
  410.       loc += (7 * nvertices);
  411.       nprimitives++;
  412.       break;
  413.     case GL_POINT_TOKEN:
  414.       loc += 7;
  415.       nprimitives++;
  416.       break;
  417.     default:
  418.       /* XXX Left as an excersie to the reader. */
  419.       printf("Incomplete implementation.  Unexpected token (%d).\n",
  420.         token);
  421.       exit(1);
  422.     }
  423.   }
  424.  
  425.   /* Allocate an array of pointers that will point back at
  426.      primitives in the feedback buffer.  There will be one
  427.      entry per primitive.  This array is also where we keep the
  428.      primitive's average depth.  There is one entry per
  429.      primitive  in the feedback buffer. */
  430.   prims = (DepthIndex *) malloc(sizeof(DepthIndex) * nprimitives);
  431.  
  432.   item = 0;
  433.   loc = buffer;
  434.   while (loc < end) {
  435.     prims[item].ptr = loc;  /* Save this primitive's location. */
  436.     token = *loc;
  437.     loc++;
  438.     switch (token) {
  439.     case GL_LINE_TOKEN:
  440.     case GL_LINE_RESET_TOKEN:
  441.       vertex = (Feedback3Dcolor *) loc;
  442.       depthSum = vertex[0].z + vertex[1].z;
  443.       prims[item].depth = depthSum / 2.0;
  444.       loc += 14;
  445.       break;
  446.     case GL_POLYGON_TOKEN:
  447.       nvertices = *loc;
  448.       loc++;
  449.       vertex = (Feedback3Dcolor *) loc;
  450.       depthSum = vertex[0].z;
  451.       for (i = 1; i < nvertices; i++) {
  452.         depthSum += vertex[i].z;
  453.       }
  454.       prims[item].depth = depthSum / nvertices;
  455.       loc += (7 * nvertices);
  456.       break;
  457.     case GL_POINT_TOKEN:
  458.       vertex = (Feedback3Dcolor *) loc;
  459.       prims[item].depth = vertex[0].z;
  460.       loc += 7;
  461.       break;
  462.     default:
  463.       /* XXX Left as an excersie to the reader. */
  464.       assert(1);
  465.     }
  466.     item++;
  467.   }
  468.   assert(item == nprimitives);
  469.  
  470.   /* Sort the primitives back to front. */
  471.   qsort(prims, nprimitives, sizeof(DepthIndex), compare);
  472.  
  473.   /* XXX Understand that sorting by a primitives average depth
  474.      doesn't allow us to disambiguate some cases like self
  475.      intersecting polygons.  Handling these cases would require
  476.      breaking up the primitives.  That's too involved for this
  477.      example.  Sorting by depth is good enough for lots of
  478.      applications. */
  479.  
  480.   /* Emit the Encapsulated PostScript for the primitives in
  481.      back to front order. */
  482.   for (item = 0; item < nprimitives; item++) {
  483.     (void) spewPrimitiveEPS(file, prims[item].ptr);
  484.   }
  485.  
  486.   free(prims);
  487. }
  488.  
  489. #define EPS_GOURAUD_THRESHOLD 0.1  /* Lower for better (slower) 
  490.  
  491.                                       smooth shading. */
  492.  
  493. void
  494. spewWireFrameEPS(FILE * file, int doSort, GLint size, GLfloat * buffer, char *creator)
  495. {
  496.   GLfloat clearColor[4], viewport[4];
  497.   GLfloat lineWidth;
  498.   int i;
  499.  
  500.   /* Read back a bunch of OpenGL state to help make the EPS
  501.      consistent with the OpenGL clear color, line width, point
  502.      size, and viewport. */
  503.   glGetFloatv(GL_VIEWPORT, viewport);
  504.   glGetFloatv(GL_COLOR_CLEAR_VALUE, clearColor);
  505.   glGetFloatv(GL_LINE_WIDTH, &lineWidth);
  506.   glGetFloatv(GL_POINT_SIZE, &pointSize);
  507.  
  508.   /* Emit EPS header. */
  509.   fputs("%!PS-Adobe-2.0 EPSF-2.0\n", file);
  510.   /* Notice %% for a single % in the fprintf calls. */
  511.   fprintf(file, "%%%%Creator: %s (using OpenGL feedback)\n", creator);
  512.   fprintf(file, "%%%%BoundingBox: %g %g %g %g\n",
  513.     viewport[0], viewport[1], viewport[2], viewport[3]);
  514.   fputs("%%EndComments\n", file);
  515.   fputs("\n", file);
  516.   fputs("gsave\n", file);
  517.   fputs("\n", file);
  518.  
  519.   /* Output Frederic Delhoume's "gouraudtriangle" PostScript
  520.      fragment. */
  521.   fputs("% the gouraudtriangle PostScript fragement below is free\n", file);
  522.   fputs("% written by Frederic Delhoume (delhoume@ilog.fr)\n", file);
  523.   fprintf(file, "/threshold %g def\n", EPS_GOURAUD_THRESHOLD);
  524.   for (i = 0; gouraudtriangleEPS[i]; i++) {
  525.     fprintf(file, "%s\n", gouraudtriangleEPS[i]);
  526.   }
  527.  
  528.   fprintf(file, "\n%g setlinewidth\n", lineWidth);
  529.  
  530.   /* Clear the background like OpenGL had it. */
  531.   fprintf(file, "%g %g %g setrgbcolor\n",
  532.     clearColor[0], clearColor[1], clearColor[2]);
  533.   fprintf(file, "%g %g %g %g rectfill\n\n",
  534.     viewport[0], viewport[1], viewport[2], viewport[3]);
  535.  
  536.   if (doSort) {
  537.     spewSortedFeedback(file, size, buffer);
  538.   } else {
  539.     spewUnsortedFeedback(file, size, buffer);
  540.   }
  541.  
  542.   /* Emit EPS trailer. */
  543.   fputs("grestore\n\n", file);
  544.   fputs("%Add `showpage' to the end of this file to be able to print to a printer.\n",
  545.     file);
  546.  
  547.   fclose(file);
  548. }
  549.  
  550. void
  551. outputEPS(int size, int doSort, char *filename)
  552. {
  553.   GLfloat *feedbackBuffer;
  554.   GLint returned;
  555.   FILE *file;
  556.  
  557.   feedbackBuffer = calloc(size, sizeof(GLfloat));
  558.   glFeedbackBuffer(size, GL_3D_COLOR, feedbackBuffer);
  559.   (void) glRenderMode(GL_FEEDBACK);
  560.   render();
  561.   returned = glRenderMode(GL_RENDER);
  562.   if (filename) {
  563.     file = fopen(filename, "w");
  564.     if (file) {
  565.       spewWireFrameEPS(file, doSort, returned, feedbackBuffer, "rendereps");
  566.     } else {
  567.       printf("Could not open %s\n", filename);
  568.     }
  569.   } else {
  570.     /* Helps debugging to be able to see the decode feedback
  571.        buffer as text. */
  572.     printBuffer(returned, feedbackBuffer);
  573.   }
  574.   free(feedbackBuffer);
  575. }
  576.  
  577. void
  578. choice(int value)
  579. {
  580.   switch (value) {
  581.   case 0:
  582.     glutSetCursor(GLUT_CURSOR_WAIT);
  583.     outputEPS(objectComplexity[object], 1, "render.eps");
  584.     glutSetCursor(GLUT_CURSOR_INHERIT);
  585.     break;
  586.   case 1:
  587.     glutSetCursor(GLUT_CURSOR_WAIT);
  588.     outputEPS(objectComplexity[object], 0, "render.eps");
  589.     glutSetCursor(GLUT_CURSOR_INHERIT);
  590.     break;
  591.   case 2:
  592.     /* Try to start GNU "ghostview" to preview the EPS. */
  593.     system("ghostview render.eps &");
  594.     break;
  595.   case 3:
  596.     glutSetCursor(GLUT_CURSOR_WAIT);
  597.     outputEPS(objectComplexity[object], 0, NULL);
  598.     glutSetCursor(GLUT_CURSOR_INHERIT);
  599.     break;
  600.   case 4:
  601.     blackBackground = 1 - blackBackground;
  602.     updateBackground();
  603.     glutPostRedisplay();
  604.     break;
  605.   case 5:
  606.     lighting = 1 - lighting;
  607.     updateLighting();
  608.     glutPostRedisplay();
  609.     break;
  610.   case 6:
  611.     polygonMode = (polygonMode + 1) % 3;
  612.     updatePolygonMode();
  613.     glutPostRedisplay();
  614.     break;
  615.   case 7:
  616.     size = (size % 5) + 1;
  617.     glLineWidth(size);
  618.     glPointSize(size);
  619.     glutPostRedisplay();
  620.     break;
  621.   case 8:
  622.     object = (object + 1) % 3;
  623.     glutPostRedisplay();
  624.     break;
  625.   case 666:
  626.     exit(0);
  627.     break;
  628.   }
  629. }
  630.  
  631. /* ARGSUSED2 */
  632. void
  633. mouse(int button, int state, int x, int y)
  634. {
  635.   if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
  636.     moving = 1;
  637.     begin = x;
  638.   }
  639.   if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) {
  640.     moving = 0;
  641.   }
  642. }
  643.  
  644. /* ARGSUSED1 */
  645. void
  646. motion(int x, int y)
  647. {
  648.   if (moving) {
  649.     angle = angle + (x - begin);
  650.     begin = x;
  651.     glutPostRedisplay();
  652.   }
  653. }
  654.  
  655. GLfloat light_diffuse[] =
  656. {0.0, 1.0, 0.0, 1.0};   /* Green light. */
  657. GLfloat light_position[] =
  658. {1.0, 1.0, 1.0, 0.0};
  659.  
  660. int
  661. main(int argc, char **argv)
  662. {
  663.   glutInit(&argc, argv);
  664.   glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGB);
  665.   glutCreateWindow("rendereps");
  666.   glutDisplayFunc(display);
  667.   glutMouseFunc(mouse);
  668.   glutMotionFunc(motion);
  669.  
  670.   glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
  671.   glLightfv(GL_LIGHT0, GL_POSITION, light_position);
  672.   glEnable(GL_LIGHT0);
  673.  
  674.   glMatrixMode(GL_PROJECTION);
  675.   gluPerspective( /* field of view in degree */ 22.0,
  676.   /* aspect ratio */ 1.0,
  677.     /* Z near */ 5.0, /* Z far */ 10.0);
  678.   glMatrixMode(GL_MODELVIEW);
  679.   gluLookAt(0.0, 0.0, 5.0,  /* eye is at (0,0,5) */
  680.     0.0, 0.0, 0.0,      /* center is at (0,0,0) */
  681.     0.0, 1.0, 0.);      /* up is in postivie Y direction */
  682.   glTranslatef(0.0, 0.0, -3.0);
  683.  
  684.   /* Give the object an "interesting" orientation. */
  685.   glRotatef(25, 1.0, 0.0, 0.0);
  686.  
  687.   glutCreateMenu(choice);
  688.   glutAddMenuEntry("Write out Encapsulated PS (sorted)", 0);
  689.   glutAddMenuEntry("Write out Encapsulated PS (UNsorted)", 1);
  690.   glutAddMenuEntry("Spawn ghostview to view EPS", 2);
  691.   glutAddMenuEntry("Display feedback buffer", 3);
  692.   glutAddMenuEntry("Toggle black/white background", 4);
  693.   glutAddMenuEntry("Toggle lighting", 5);
  694.   glutAddMenuEntry("Switch fill mode (line, poly, point)", 6);
  695.   glutAddMenuEntry("Switch line/point size", 7);
  696.   glutAddMenuEntry("Switch object", 8);
  697.   glutAddMenuEntry("Quit", 666);
  698.   glutAttachMenu(GLUT_RIGHT_BUTTON);
  699.  
  700.   updateBackground();
  701.   updateLighting();
  702.   updatePolygonMode();
  703.  
  704.   glEnable(GL_DEPTH_TEST);
  705.   glColor3f(1.0, 0.0, 0.0);  /* Geometry should appear red. */
  706.  
  707.   glutMainLoop();
  708.   return 0;             /* ANSI C requires main to return int. */
  709. }
  710.